﻿/*
 * LINQ to LDAP
 * http://linqtoldap.codeplex.com/
 * 
 * Copyright Alan Hatter (C) 2010-2012
 * alan.hatter@gmail.com - http://hattercoding.blogspot.com/
 * 
 * This project is subject to licensing restrictions. Visit http://linqtoldap.codeplex.com/license for more information.
 */

using System;
using System.DirectoryServices.Protocols;
using System.Linq.Expressions;
using LinqToLdap.Logging;
using LinqToLdap.Mapping;
using LinqToLdap.QueryCommands;
using LinqToLdap.Visitors;

namespace LinqToLdap
{
    internal class DirectoryQueryProvider : QueryProvider, IDisposable
    {
        private bool _disposed;
        private IObjectMapping _mapping;
        private readonly SearchScope _scope;
        private LdapConnection _conneciton;
        private bool _pagingEnabled;

        public DirectoryQueryProvider(LdapConnection connection, SearchScope scope, IObjectMapping mapping, bool pagingEnabled)
        {
            if (mapping == null) throw new ArgumentNullException("mapping");
            if (connection == null) throw new ArgumentNullException("connection");

            _scope = scope;
            _conneciton = connection;
            _mapping = mapping;
            _pagingEnabled = pagingEnabled;
        }

        public ILinqToLdapLogger Log { private get; set; }

        public bool IsDynamic { private get; set; }

        public int MaxPageSize { get; set; }

        public string NamingContext { get; set; }

        private IQueryCommand TranslateExpression(Expression expression)
        {
            if (Log != null && Log.TraceEnabled) Log.Trace("Expression: " + expression);

            var translator = new QueryTranslator(_mapping) {IsDynamic = IsDynamic};
            return translator.Translate(expression);
        }

        public override string GetQueryText(Expression expression)
        {
            var translated = TranslateExpression(expression);

            return translated.ToString();
        }

        public override object Execute(Expression expression)
        {
            try
            {
                if (_disposed) throw new ObjectDisposedException(GetType().FullName);
                var executor = TranslateExpression(expression);
                return executor.Execute(_conneciton, _scope, MaxPageSize, _pagingEnabled, Log, NamingContext);
            }
            catch (Exception ex)
            {
                if (Log != null) Log.Error(ex);
                throw;
            }
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        /// <filterpriority>2</filterpriority>
        public void Dispose()
        {
            _mapping = null;
            _conneciton = null;
            Log = null;
            _disposed = true;
        }
    }
}
